﻿namespace Scheduler.Library
{
    using System;
    using System.Timers;
    using System.Threading;

    /// <summary>
    /// 表示一个可调度的任务
    /// </summary>
    public class SchedulerTask
    {
        #region 私有属性

        /// <summary>
        /// 调用次数
        /// </summary>
        private int _callCount = 0;

        /// <summary>
        /// 最后调用时间
        /// </summary>
        private DateTime _lastCallTime = DateTime.MinValue;

        /// <summary>
        /// 最后调用至当前调用的间隔时间
        /// </summary>
        private TimeSpan _lastCallElapsedTime = TimeSpan.MinValue;

        #endregion

        /// <summary>
        /// 任务的名称
        /// </summary>
        public string Name { get; set; }

        /// <summary>
        /// 任务指定的动作
        /// </summary>
        public Action OnTaskExecute { get; set; }

        /// <summary>
        /// 当一个任务完成时调用的动作
        /// </summary>
        public Action<SchedulerTask> OnTaskCompleted { get; set; }

        /// <summary>
        /// 触发器
        /// </summary>
        public Trigger Trigger { get; set; }

        /// <summary>
        /// 计时器
        /// </summary>
        public System.Timers.Timer TaskTimer { get; set; }

        /// <summary>
        /// 初始化<see cref="SchedulerTask"/>
        /// </summary>
        /// <param name="name">任务名</param>
        /// <param name="executor">任务内容</param>
        /// <param name="trigger">触发器</param>
        public SchedulerTask(string name, Action executor, Trigger trigger)
        {
            Name = name;
            Trigger = trigger;
            OnTaskExecute = executor;
        }

        /// <summary>
        /// 定时时间到时触发的动作（启动任务或者满足条件停止任务）
        /// </summary>
        /// <param name="sender">事件源。</param>
        /// <param name="e">包含事件数据的 System.Timers.ElapsedEventArgs 对象。</param>
        public void OnTimerElapsed(object sender, ElapsedEventArgs e)
        {
            // 如果任务被调用次数已经超过了最大迭代限制则停止         
            if (Trigger.HasMaxIterations && _callCount >= Trigger.MaxIterations)
            {
                Stop();
                return;
            }
            // 如果当前时间超过结束时间则停止
            else if (Trigger.EndTime != DateTime.MinValue && e.SignalTime >= Trigger.EndTime)
            {
                Stop();
                return;
                // 如果设置了任务的开始时间，且没有达到开始时间，则不触发，等待下一次timer触发事件
            }
            else if (Trigger.StartTime != DateTime.MinValue && e.SignalTime < Trigger.StartTime)
            {
                return;
            }

            Run();

            // 如果任务不重复执行，就停止
            if (!Trigger.Repeat || Trigger.IsOnDemand)
            {
                Stop();
            }
        }

        /// <summary>
        /// 启动任务
        /// </summary>
        public void Run()
        {
            // 执行任务动作
            OnTaskExecute();

            // 更新当前任务摘要
            UpdateSummary();
        }

        /// <summary>
        /// 获取任务状态
        /// </summary>
        /// <returns>返回状态信息</returns>
        public TaskSummary GetStatus()
        {
            var isEnabled = IsOnDemand || TaskTimer.Enabled;
            return new TaskSummary(Name, _lastCallTime, _callCount, _lastCallElapsedTime, isEnabled);
        }

        /// <summary>
        /// 该任务是否为一个主动运行任务
        /// </summary>
        /// <returns>如果为真表示该任务是一个主动运行任务，需要手工启动</returns>
        public bool IsOnDemand => this.Trigger.IsOnDemand;

        /// <summary>
        /// 停止计时，并回调任务完成函数
        /// </summary>
        private void Stop()
        {
            try
            {
                TaskTimer.Stop();

                if (OnTaskCompleted == null) return;
                var copy = Copy(this);
                OnTaskCompleted(copy);
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }

        /// <summary>
        /// 更新任务摘要
        /// </summary>
        private void UpdateSummary()
        {
            // 累加任务被调用的次数
            Interlocked.Increment(ref _callCount);

            DateTime now = DateTime.Now;

            // 重置最后调用至当前调用的间隔时间
            if (_lastCallTime != DateTime.MinValue)
            {
                _lastCallElapsedTime = now.TimeOfDay - _lastCallTime.TimeOfDay;
            }
            _lastCallTime = now;
        }

        /// <summary>
        /// 复制指定的任务
        /// </summary>
        /// <param name="task">需要复制的对象</param>
        /// <returns>返回复制后的任务实例</returns>
        public static SchedulerTask Copy(SchedulerTask task)
        {
            SchedulerTask copy = new SchedulerTask(task.Name, task.OnTaskExecute, task.Trigger.Clone() as Trigger);
            return copy;
        }
    }
}
